package demo.ioc.my.core.ctx;

import demo.ioc.Main;
import demo.ioc.my.core.annotation.Autowired;
import demo.ioc.my.core.annotation.Component;
import demo.ioc.my.core.annotation.Configuration;
import demo.ioc.my.core.annotation.Controller;
import demo.ioc.my.core.annotation.Repository;
import demo.ioc.my.core.annotation.Service;

import java.io.File;
import java.io.IOException;
import java.lang.reflect.Field;
import java.net.URISyntaxException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.time.LocalDateTime;
import java.util.stream.Stream;

/**
 * Created by 张少昆 on 2018/3/18.
 */
public class DefaultApplicationContext extends AbstractApplicationContext {


    public DefaultApplicationContext(){
        System.out.println("ApplicationContext 启动开始..@" + LocalDateTime.now());
        init();

        //还要添加自己！ 简化，不需要了。
        // CLASS_INSTANCE_MAP.put(this.getClass(), this);
        // CLASS_LIST.add(this.getClass());

        System.out.println("ApplicationContext 启动完毕..@" + LocalDateTime.now());
        // System.out.println(CLASS_INSTANCE_MAP);
        // System.out.println(CLASS_LIST);
    }

    public void init(){
        Path path = null;
        try{
            path = Paths.get(Main.class.getResource(".").toURI());
        } catch(URISyntaxException e){
            e.printStackTrace();
        }
        String prefix = path.toFile().getPath() + File.separator;

        // System.out.println("---");
        Stream<Path> stream = null;
        try{
            stream = Files.walk(path);
        } catch(IOException e){
            e.printStackTrace();
        }
        // stream.filter(e -> e.endsWith("class") ) //FIXME path.endsWith 判断的是path，不是字符串，靠
        //                      .forEach(System.out::println);
        String pkg_prefix = Main.class.getPackage().getName();

        //扫描、并创建bean！
        System.out.println("开始扫描并创建bean...@" + LocalDateTime.now());
        stream
                .map(Path::toFile)
                .filter(file -> file.canRead() && file.isFile() && file.getName().endsWith(".class"))
                .map(e -> {
                    String tmp = pkg_prefix + "." + e
                                                            .getPath()
                                                            .substring(prefix.length())
                                                            .replace(File.separatorChar, '.')
                                                            .replace(".class", "");
                    Class<?> clz = null;
                    try{
                        clz = Class.forName(tmp);
                    } catch(ClassNotFoundException e1){
                        e1.printStackTrace();
                    }
                    return clz;
                })
                .filter(e -> e.isAnnotationPresent(Component.class) || e.isAnnotationPresent(Controller.class) || e.isAnnotationPresent(Service.class) || e.isAnnotationPresent(Repository.class) || e.isAnnotationPresent(Configuration.class))
                .filter(e -> !e.isInterface())
                .forEach(e -> {
                    CLASS_LIST.add(e); //

                    // Class<?> superclass = e.getSuperclass();
                    // Class<?>[] classes = e.getClasses();//member
                    Class<?>[] interfaces = e.getInterfaces();

                    try{
                        Object obj = e.newInstance();
                        CLASS_INSTANCE_MAP.put(e, obj);//光这样还不够，还要存储其实现的接口的！
                        for(Class<?> anInterface : interfaces){
                            CLASS_INSTANCE_MAP.put(anInterface, obj);
                        }
                    } catch(InstantiationException e1){
                        e1.printStackTrace();
                    } catch(IllegalAccessException e1){
                        e1.printStackTrace();
                    }
                });
        System.out.println("完成扫描并创建bean...@" + LocalDateTime.now());

        System.out.println("开始注入bean...@" + LocalDateTime.now());
        //实现注入
        CLASS_LIST.forEach(e -> {
            Field[] fields = e.getDeclaredFields();
            for(Field field : fields){
                if(field.isAnnotationPresent(Autowired.class)){
                    // Autowired declaredAnnotation = field.getDeclaredAnnotation(Autowired.class); //不这么用，简化
                    try{
                        field.setAccessible(true);
                        // System.out.println(map.get(e) + " -- " + map.get(field.getDeclaringClass()));
                        field.set(CLASS_INSTANCE_MAP.get(e), CLASS_INSTANCE_MAP.get(field.getType()));//key point
                    } catch(IllegalAccessException e1){
                        e1.printStackTrace();
                    }

                }
            }
        });
        System.out.println("完成注入bean...@" + LocalDateTime.now());

    }


}
